import { ReactiveEffect, trackOpBit } from "./effect";

export type Dep = Set<ReactiveEffect> & TrackedMarkers;

/**
 * wasTracked and newTracked maintain the status for several levels of effect
 * tracking recursion. One bit per level is used to define whether the dependency
 * was/is tracked.
 */
type TrackedMarkers = {
  /**
   * wasTracked
   */
  w: number;
  /**
   * newTracked
   */
  n: number;
};

export const createDep = (effects?: ReactiveEffect[]): Dep => {
  /**
   * 字如其名：
   *  映射：存储的是类型键值对的关系 对标的是 对象
   *  集合：存储的是一个个值的关系  对标的是  数组
   */
  /**
   * 创建一个存储 effects 副作用函数的 集合
   *  这里使用集合还有一个好处，能防止有时候因为代码错误而多添加一个相同的effect函数
   *  能够自动去除重复的 effect
   */
  const dep = new Set<ReactiveEffect>(effects) as Dep;
  dep.w = 0;
  dep.n = 0;
  return dep;
};

export const wasTracked = (dep: Dep): boolean => (dep.w & trackOpBit) > 0;

export const newTracked = (dep: Dep): boolean => (dep.n & trackOpBit) > 0;

export const initDepMarkers = ({ deps }: ReactiveEffect) => {
  if (deps.length) {
    for (let i = 0; i < deps.length; i++) {
      deps[i].w |= trackOpBit; // set was tracked
    }
  }
};

export const finalizeDepMarkers = (effect: ReactiveEffect) => {
  const { deps } = effect;
  if (deps.length) {
    let ptr = 0;
    for (let i = 0; i < deps.length; i++) {
      const dep = deps[i];
      if (wasTracked(dep) && !newTracked(dep)) {
        dep.delete(effect);
      } else {
        deps[ptr++] = dep;
      }
      // clear bits
      dep.w &= ~trackOpBit;
      dep.n &= ~trackOpBit;
    }
    deps.length = ptr;
  }
};
